package nape.geom;
import nape.geom.Axis;
import nape.geom.Mat23;
import nape.geom.Vec2;
import nape.geom.VecMath;
import nape.util.FastMath;
import nape.util.MixPool;
import nape.util.Names;
import nape.util.NpAlgorithm;
import nape.util.NpList;
import nape.Const;
import nape.Config;
import nape.util.NpNode_ZNContact;
import nape.util.NpAllocList_ZNContact;
import nape.util.NpNode_ZNV2;
import nape.util.NpList_ZNV2;
import nape.util.NpNode_Vec2__Dynamic;
import nape.util.NpList_Vec2__Dynamic;
import nape.util.NpNode_ZNShp;
import nape.util.NpList_ZNShp;










class AABB {
    public var znp_inner:ZNAB;
    
    
    
    public function new(?x:Float=0,?y:Float=0,?width:Float=0,?height:Float=0)
    {
        znp_inner = new ZNAB(x,y,x+width,y+height);
        znp_inner.outer = this;
    }
    
    #if flash
        public static inline function fromRect(rect:flash.geom.Rectangle) {
            return new AABB(rect.x,rect.y,rect.width,rect.height);
        }
    #end
    
    
    
    public var znp_broadcast:AABB->Dynamic;
    
    
    
    public var x(get_x,set_x):Float;
    public var y(get_y,set_y):Float;
    public var width (get_width, set_width) :Float;
    public var height(get_height,set_height):Float;
    
    public var min(get_min,never):Vec2;
    public var max(get_max,never):Vec2;
    
    
    
    public inline function get_x() return znp_inner.minx
    public inline function get_y() return znp_inner.miny
    public inline function get_width () return znp_inner.width()
    public inline function get_height() return znp_inner.height()
    
    
    
    public inline function set_x(x:Float) {
        if(this.x!=x) {
            znp_inner.minx = x;
            if(znp_broadcast!=null) znp_broadcast(this);
            if(znp_inner.wrap_min!=null) znp_inner.wrap_min.znp_inner.x = x;
        }
        return x;
    }
    public inline function set_y(y:Float) {
        if(this.y!=y) {
            znp_inner.miny = y;
            if(znp_broadcast!=null) znp_broadcast(this);
            if(znp_inner.wrap_min!=null) znp_inner.wrap_min.znp_inner.y = y;
        }
        return y;
    }
    
    
    
    public inline function set_width(width:Float) {
        if(this.width!=width) {
            znp_inner.maxx = x+width;
            if(znp_broadcast!=null) znp_broadcast(this);
            if(znp_inner.wrap_max!=null)
                znp_inner.wrap_max.znp_inner.x = znp_inner.maxx;
        }
        return width;
    }
    public inline function set_height(height:Float) {
        if(this.height!=height) {
            znp_inner.maxy = y+height;
            if(znp_broadcast!=null) znp_broadcast(this);
            if(znp_inner.wrap_max!=null)
                znp_inner.wrap_max.znp_inner.y = znp_inner.maxy;
        }
        return height;
    }
    
    
    
    public inline function get_min() return znp_inner.get_min()
    public inline function get_max() return znp_inner.get_max()
}



class ZNAB {
    public var outer:AABB;
    
    

    public function new(minx:Float,miny:Float,maxx:Float,maxy:Float) {
            { this.minx = minx; this.miny = miny; };
            { this.maxx = maxx; this.maxy = maxy; };
    }
    
    
    
    public inline function wrapper() {
        if(outer!=null) return outer;
        else {
            outer = new AABB();
            outer.znp_inner = this;
            return outer;
        }
    }
    
    
    
    public inline function width () return maxx-minx
    public inline function height() return maxy-miny
    
    
    
    
    
    
    
         public var minx:Float; public var miny:Float;
        public var wrap_min:Vec2;
        
        public inline function get_min() {
            if(wrap_min==null) {
                wrap_min = new Vec2(minx,miny);
                wrap_min.znp_broadcast.add(mod_min);
            }
            return wrap_min;
        }
        public inline function mod_min(min:Vec2) {
            if(min.x != minx || min.y != miny) {
                    { minx = min.x; miny = min.y; };
                if(outer!=null && outer.znp_broadcast!=null)
                    outer.znp_broadcast(outer);
            }
        }
    
    
    
         public var maxx:Float; public var maxy:Float;
        public var wrap_max:Vec2;
        
        public inline function get_max() {
            if(wrap_max==null) {
                wrap_max = new Vec2(maxx,maxy);
                wrap_max.znp_broadcast.add(mod_max);
            }
            return wrap_max;
        }
        public inline function mod_max(max:Vec2) {
            if(max.x != maxx || max.y != maxy) {
                    { maxx = max.x; maxy = max.y; };
                if(outer!=null && outer.znp_broadcast!=null)
                    outer.znp_broadcast(outer);
            }
        }
    
}
